// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package ssa

import (
	"cmd/compile/internal/logopt"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/obj/s390x"
	"cmd/internal/objabi"
	"cmd/internal/src"
	"encoding/binary"
	"fmt"
	"io"
	"math"
	"math/bits"
	"os"
	"path/filepath"
)

type deadValueChoice bool

const (
	leaveDeadValues  deadValueChoice = false
	removeDeadValues                 = true
)

// deadcode指示重写是否应尝试删除任何已失效的值。
func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValueChoice) {
	// 重复重写，直到找不到更多的重写
	pendingLines := f.cachedLineStarts // 保存需要移动到新值/块的语句边界
	pendingLines.clear()
	debug := f.pass.debug
	if debug > 1 {
		fmt.Printf("%s: rewriting for %s\n", f.pass.name, f.Name)
	}
	for {
		change := false
		for _, b := range f.Blocks {
			var b0 *Block
			if debug > 1 {
				b0 = new(Block)
				*b0 = *b
				b0.Succs = append([]Edge{}, b.Succs...) // 创建新副本，而不是别名
			}
			for i, c := range b.ControlValues() {
				for c.Op == OpCopy {
					c = c.Args[0]
					b.ReplaceControl(i, c)
				}
			}
			if rb(b) {
				change = true
				if debug > 1 {
					fmt.Printf("rewriting %s  ->  %s\n", b0.LongString(), b.LongString())
				}
			}
			for j, v := range b.Values {
				var v0 *Value
				if debug > 1 {
					v0 = new(Value)
					*v0 = *v
					v0.Args = append([]*Value{}, v.Args...) // 创建新副本，而不是别名
				}
				if v.Uses == 0 && v.removeable() {
					if v.Op != OpInvalid && deadcode == removeDeadValues {
						// 重置所有现在未使用的值，以便减少
						// 其所有参数的使用计数。
						// 不完全是死代码传递，因为它不处理循环。
						// 但它应该有助于使用==1规则触发。
						v.reset(OpInvalid)
						change = true
					}
					// 无点重写未使用的值。
					continue
				}

				vchange := phielimValue(v)
				if vchange && debug > 1 {
					fmt.Printf("rewriting %s  ->  %s\n", v0.LongString(), v.LongString())
				}

				// 消除复制输入。
				// 如果任何副本输入变得未使用，请标记它
				// 视为无效并放弃其论点。重复
				// 递归地处理丢弃的参数。
				// 此阶段有助于删除虚拟“死拷贝”使用
				// 使x.Uses==1规则条件
				// 发射可靠。
				for i, a := range v.Args {
					if a.Op != OpCopy {
						continue
					}
					aa := copySource(a)
					v.SetArg(i, aa)
					// 如果副本具有行边界指示器，请尝试查找新值
					// 拿着它。第一个候选值是将替换a（aa）的值，
					// 如果它共享同一块和线并且符合条件。
					// 第二个选项是v，它的输入是a。因为aa是早期的
					// 在数据流方面，它是更好的选择。
					if a.Pos.IsStmt() == src.PosIsStmt {
						if aa.Block == a.Block && aa.Pos.Line() == a.Pos.Line() && aa.Pos.IsStmt() != src.PosNotStmt {
							aa.Pos = aa.Pos.WithIsStmt()
						} else if v.Block == a.Block && v.Pos.Line() == a.Pos.Line() && v.Pos.IsStmt() != src.PosNotStmt {
							v.Pos = v.Pos.WithIsStmt()
						} else {
							// 记录丢失的行，并在所有重写完成后寻找新家。
							// TODO:同样的语句边界也是可能的（特别是在FOR循环中）
							// 行显示在多个块中，但只存储一个块，所以如果两个块都结束
							// 在这里，一个会丢失。
							pendingLines.set(a.Pos, int32(a.Block.ID))
						}
						a.Pos = a.Pos.WithNotStmt()
					}
					vchange = true
					for a.Uses == 0 {
						b := a.Args[0]
						a.reset(OpInvalid)
						a = b
					}
				}
				if vchange && debug > 1 {
					fmt.Printf("rewriting %s  ->  %s\n", v0.LongString(), v.LongString())
				}

				// 应用重写函数
				if rv(v) {
					vchange = true
					// 如果语句边界的值更改为较差的选择，请移动边界
					if v.Pos.IsStmt() == src.PosIsStmt {
						if k := nextGoodStatementIndex(v, j, b); k != j {
							v.Pos = v.Pos.WithNotStmt()
							b.Values[k].Pos = b.Values[k].Pos.WithIsStmt()
						}
					}
				}

				change = change || vchange
				if vchange && debug > 1 {
					fmt.Printf("rewriting %s  ->  %s\n", v0.LongString(), v.LongString())
				}
			}
		}
		if !change {
			break
		}
	}
	// 删除被删除的值
	for _, b := range f.Blocks {
		j := 0
		for i, v := range b.Values {
			vl := v.Pos
			if v.Op == OpInvalid {
				if v.Pos.IsStmt() == src.PosIsStmt {
					pendingLines.set(vl, int32(b.ID))
				}
				f.freeValue(v)
				continue
			}
			if v.Pos.IsStmt() != src.PosNotStmt && !notStmtBoundary(v.Op) && pendingLines.get(vl) == int32(b.ID) {
				pendingLines.remove(vl)
				v.Pos = v.Pos.WithIsStmt()
			}
			if i != j {
				b.Values[j] = v
			}
			j++
		}
		if pendingLines.get(b.Pos) == int32(b.ID) {
			b.Pos = b.Pos.WithIsStmt()
			pendingLines.remove(b.Pos)
		}
		b.truncateValues(j)
	}
}

// 从重写规则调用的公共函数

func is64BitFloat(t *types.Type) bool {
	return t.Size() == 8 && t.IsFloat()
}

func is32BitFloat(t *types.Type) bool {
	return t.Size() == 4 && t.IsFloat()
}

func is64BitInt(t *types.Type) bool {
	return t.Size() == 8 && t.IsInteger()
}

func is32BitInt(t *types.Type) bool {
	return t.Size() == 4 && t.IsInteger()
}

func is16BitInt(t *types.Type) bool {
	return t.Size() == 2 && t.IsInteger()
}

func is8BitInt(t *types.Type) bool {
	return t.Size() == 1 && t.IsInteger()
}

func isPtr(t *types.Type) bool {
	return t.IsPtrShaped()
}

func isSigned(t *types.Type) bool {
	return t.IsSigned()
}

// mergeSym合并两个符号偏移。没有真正的合并
// 偏移量，我们只选择非零的。
func mergeSym(x, y Sym) Sym {
	if x == nil {
		return y
	}
	if y == nil {
		return x
	}
	panic(fmt.Sprintf("mergeSym with two non-nil syms %v %v", x, y))
}

func canMergeSym(x, y Sym) bool {
	return x == nil || y == nil
}

// canMergeLoadClobber报告是否可以将负载合并到目标中而无需
// 使时间表无效。
// 它还检查另一个非加载参数x是否是我们需要的参数
// 你可以击打。
func canMergeLoadClobber(target, load, x *Value) bool {
	// 包含x的寄存器将被删除。
	// 如果仍然需要x的值，请不要合并。
	// 我们这里没有活性信息，但我们可以
	// 近似x染色，带有：
	// 1） 目标是x的唯一用途。
	// 2） 目标不在比x更深的循环中。
	if x.Uses != 1 {
		return false
	}
	loopnest := x.Block.Func.loopnest()
	loopnest.calculateDepths()
	if loopnest.depth(target.Block.ID) > loopnest.depth(x.Block.ID) {
		return false
	}
	return canMergeLoad(target, load)
}

// canMergeLoad报告负载是否可以合并到目标中，而无需
// 使时间表无效。
func canMergeLoad(target, load *Value) bool {
	if target.Block.ID != load.Block.ID {
		// 如果加载位于不同的块中，请不要将其合并。
		return false
	}

	// 如果加载失败，则无法将加载合并到目标中
	// 有不止一个用途。
	if load.Uses != 1 {
		return false
	}

	mem := load.MemoryArg()

	// 我们需要负载的内存arg在目标位置仍处于活动状态。那个
	// 如果目标的某个参数依赖于内存，则不会出现这种情况
	// 作为加载的内存arg的后续项的状态。
	// None
	// 例如，将加载合并到中的目标是无效的
	// 以下情况是因为newmem杀了oldmem
	// 在达到目标之前：
	// 加载=读取。。。奥德姆
	// newmem=写入。。。奥德姆
	// arg0=读取。。。纽曼
	// 目标=添加arg0加载
	// None
	// 如果参数来自不同的块，那么我们可以排除
	// 因为它必须控制负载（在
	// 与目标相同的块）。
	var args []*Value
	for _, a := range target.Args {
		if a != load && a.Block.ID == target.Block.ID {
			args = append(args, a)
		}
	}

	// memPreds包含已知为load的前级的内存状态
	// 内存状态。它是惰性初始化的。
	var memPreds map[*Value]bool
	for i := 0; len(args) > 0; i++ {
		const limit = 100
		if i >= limit {
			// 如果我们做了很多迭代，就放弃。
			return false
		}
		v := args[len(args)-1]
		args = args[:len(args)-1]
		if target.Block.ID != v.Block.ID {
			// 因为目标和加载在同一块中
			// 我们可以在离开街区时停止搜索。
			continue
		}
		if v.Op == OpPhi {
			// Phi意味着我们已经到达了街区的顶端。
			// 内存phi（如果存在）始终为
			// 块中的第一个逻辑存储。
			continue
		}
		if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
			// 我们可以处理这种情况，不管它有多大可能
			// 非常罕见。
			return false
		}
		if v.Op.SymEffect()&SymAddr != 0 {
			// 这种情况下，无法执行计算
			// 被强制调度的局部变量的地址
			// 在其相应的VarDef之前。
			// 见第28445期。
			// v1=加载。。。
			// v2=VARDEF
			// v3=LEAQ
			// v4=CMPQ v1 v3
			// 我们不想将CMPQ与负载相结合，因为
			// 这将迫使CMPQ在VARDEF之前进行调度，而VARDEF
			// 反过来，要求LEAQ在VARDEF之前进行计划。
			return false
		}
		if v.Type.IsMemory() {
			if memPreds == nil {
				// 初始化包含内存状态的映射
				// 已知是load记忆的前身
				// 状态
				memPreds = make(map[*Value]bool)
				m := mem
				const limit = 50
				for i := 0; i < limit; i++ {
					if m.Op == OpPhi {
						// 内存phi（如果存在）始终为
						// 块中的第一个逻辑存储。
						break
					}
					if m.Block.ID != target.Block.ID {
						break
					}
					if !m.Type.IsMemory() {
						break
					}
					memPreds[m] = true
					if len(m.Args) == 0 {
						break
					}
					m = m.MemoryArg()
				}
			}

			// 如果v是mem的前身，我们可以合并。
			// None
			// 例如，我们可以在
			// 以下场景：
			// x=读取。。。五、
			// mem=写入。。。五、
			// 加载=读取。。。记忆
			// 目标=添加x负载
			if memPreds[v] {
				continue
			}
			return false
		}
		if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem {
			// 如果v将mem作为输入，那么我们就知道mem
			// 在这一点上是有效的。
			continue
		}
		for _, a := range v.Args {
			if target.Block.ID == a.Block.ID {
				args = append(args, a)
			}
		}
	}

	return true
}

// isSameCall报告sym是否与给定的命名符号相同
func isSameCall(sym interface{}, name string) bool {
	fn := sym.(*AuxCall).Fn
	return fn != nil && fn.String() == name
}

// nlz返回前导零的数目。
func nlz64(x int64) int { return bits.LeadingZeros64(uint64(x)) }
func nlz32(x int32) int { return bits.LeadingZeros32(uint32(x)) }
func nlz16(x int16) int { return bits.LeadingZeros16(uint16(x)) }
func nlz8(x int8) int   { return bits.LeadingZeros8(uint8(x)) }

// ntzX返回尾随零的数目。
func ntz64(x int64) int { return bits.TrailingZeros64(uint64(x)) }
func ntz32(x int32) int { return bits.TrailingZeros32(uint32(x)) }
func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) }
func ntz8(x int8) int   { return bits.TrailingZeros8(uint8(x)) }

func oneBit(x int64) bool   { return x&(x-1) == 0 && x != 0 }
func oneBit8(x int8) bool   { return x&(x-1) == 0 && x != 0 }
func oneBit16(x int16) bool { return x&(x-1) == 0 && x != 0 }
func oneBit32(x int32) bool { return x&(x-1) == 0 && x != 0 }
func oneBit64(x int64) bool { return x&(x-1) == 0 && x != 0 }

// nto返回尾随数。
func nto(x int64) int64 {
	return int64(ntz64(^x))
}

// logX返回n以2为底的对数。
// n必须是2的正幂（ispowerroftwox返回true）。
func log8(n int8) int64 {
	return int64(bits.Len8(uint8(n))) - 1
}
func log16(n int16) int64 {
	return int64(bits.Len16(uint16(n))) - 1
}
func log32(n int32) int64 {
	return int64(bits.Len32(uint32(n))) - 1
}
func log64(n int64) int64 {
	return int64(bits.Len64(uint64(n))) - 1
}

// log2uint32返回uint32（n）以2为底的对数，其中log2（0）=-1。
// 四舍五入。
func log2uint32(n int64) int64 {
	return int64(bits.Len32(uint32(n))) - 1
}

// isPowerOfTwo函数报告n是否为2的幂。
func isPowerOfTwo8(n int8) bool {
	return n > 0 && n&(n-1) == 0
}
func isPowerOfTwo16(n int16) bool {
	return n > 0 && n&(n-1) == 0
}
func isPowerOfTwo32(n int32) bool {
	return n > 0 && n&(n-1) == 0
}
func isPowerOfTwo64(n int64) bool {
	return n > 0 && n&(n-1) == 0
}

// Isuint64幂函数两个报告uint64（n）是否为2的幂。
func isUint64PowerOfTwo(in int64) bool {
	n := uint64(in)
	return n > 0 && n&(n-1) == 0
}

// Isuint32 power of two报告uint32（n）是否为2的幂。
func isUint32PowerOfTwo(in int64) bool {
	n := uint64(uint32(in))
	return n > 0 && n&(n-1) == 0
}

// IS32位报告n是否可以表示为有符号32位整数。
func is32Bit(n int64) bool {
	return n == int64(int32(n))
}

// is16Bit报告n是否可以表示为有符号16位整数。
func is16Bit(n int64) bool {
	return n == int64(int16(n))
}

// is8Bit报告n是否可以表示为有符号8位整数。
func is8Bit(n int64) bool {
	return n == int64(int8(n))
}

// isU8Bit报告n是否可以表示为无符号8位整数。
func isU8Bit(n int64) bool {
	return n == int64(uint8(n))
}

// isU12Bit报告n是否可以表示为无符号12位整数。
func isU12Bit(n int64) bool {
	return 0 <= n && n < (1<<12)
}

// isU16Bit报告n是否可以表示为无符号16位整数。
func isU16Bit(n int64) bool {
	return n == int64(uint16(n))
}

// isU32Bit报告n是否可以表示为无符号32位整数。
func isU32Bit(n int64) bool {
	return n == int64(uint32(n))
}

// is20Bit报告n是否可以表示为带符号的20位整数。
func is20Bit(n int64) bool {
	return -(1<<19) <= n && n < (1<<19)
}

// b2i将布尔值转换为0或1以分配给生长素。
func b2i(b bool) int64 {
	if b {
		return 1
	}
	return 0
}

// b2i32将布尔值转换为0或1。
func b2i32(b bool) int32 {
	if b {
		return 1
	}
	return 0
}

// shiftIsBounded报告（左/右）移位值v是否已知有界。
// 如果移位小于移位值的宽度，则移位是有界的。
func shiftIsBounded(v *Value) bool {
	return v.AuxInt != 0
}

// 为了规范化，canonLessThan返回x是否“有序”小于y
// 尽可能多地生成代码。
func canonLessThan(x, y *Value) bool {
	if x.Op != y.Op {
		return x.Op < y.Op
	}
	if !x.Pos.SameFileAndLine(y.Pos) {
		return x.Pos.Before(y.Pos)
	}
	return x.ID < y.ID
}

// truncate64Fto32F将浮点64值转换为保留位模式的浮点32
// 尾数。如果截断导致信息丢失，它将陷入恐慌。
func truncate64Fto32F(f float64) float32 {
	if !isExactFloat32(f) {
		panic("truncate64Fto32F: truncation is not exact")
	}
	if !math.IsNaN(f) {
		return float32(f)
	}
	// NaN位模式不一定在转换过程中保持不变
	// 所以我们需要手动进行转换。
	b := math.Float64bits(f)
	m := b & ((1 << 52) - 1) // 尾数（又称有效位）
	// |符号|指数|尾数|
	r := uint32(((b >> 32) & (1 << 31)) | 0x7f800000 | (m >> (52 - 23)))
	return math.Float32frombits(r)
}

// extend32Fto64F将float32值转换为保留位的float64值
// 尾数的图案。
func extend32Fto64F(f float32) float64 {
	if !math.IsNaN(float64(f)) {
		return float64(f)
	}
	// NaN位模式不一定在转换过程中保持不变
	// 所以我们需要手动进行转换。
	b := uint64(math.Float32bits(f))
	// |符号|指数|尾数|
	r := ((b << 32) & (1 << 63)) | (0x7ff << 52) | ((b & 0x7fffff) << (52 - 23))
	return math.Float64frombits(r)
}

// 部门需要修复报告部门是否需要修复代码。
func DivisionNeedsFixUp(v *Value) bool {
	return v.AuxInt == 0
}

// auxFrom64F对float64值进行编码，以便将其存储在生长素中。
func auxFrom64F(f float64) int64 {
	if f != f {
		panic("can't encode a NaN in AuxInt field")
	}
	return int64(math.Float64bits(f))
}

// auxFrom32F对float32值进行编码，以便将其存储在生长素中。
func auxFrom32F(f float32) int64 {
	if f != f {
		panic("can't encode a NaN in AuxInt field")
	}
	return int64(math.Float64bits(extend32Fto64F(f)))
}

// auxTo32F根据提供的生长素值对float32进行解码。
func auxTo32F(i int64) float32 {
	return truncate64Fto32F(math.Float64frombits(uint64(i)))
}

// auxTo64F根据提供的生长素值对浮点64进行解码。
func auxTo64F(i int64) float64 {
	return math.Float64frombits(uint64(i))
}

func auxIntToBool(i int64) bool {
	if i == 0 {
		return false
	}
	return true
}
func auxIntToInt8(i int64) int8 {
	return int8(i)
}
func auxIntToInt16(i int64) int16 {
	return int16(i)
}
func auxIntToInt32(i int64) int32 {
	return int32(i)
}
func auxIntToInt64(i int64) int64 {
	return i
}
func auxIntToUint8(i int64) uint8 {
	return uint8(i)
}
func auxIntToFloat32(i int64) float32 {
	return float32(math.Float64frombits(uint64(i)))
}
func auxIntToFloat64(i int64) float64 {
	return math.Float64frombits(uint64(i))
}
func auxIntToValAndOff(i int64) ValAndOff {
	return ValAndOff(i)
}
func auxIntToArm64BitField(i int64) arm64BitField {
	return arm64BitField(i)
}
func auxIntToInt128(x int64) int128 {
	if x != 0 {
		panic("nonzero int128 not allowed")
	}
	return 0
}
func auxIntToFlagConstant(x int64) flagConstant {
	return flagConstant(x)
}

func auxIntToOp(cc int64) Op {
	return Op(cc)
}

func boolToAuxInt(b bool) int64 {
	if b {
		return 1
	}
	return 0
}
func int8ToAuxInt(i int8) int64 {
	return int64(i)
}
func int16ToAuxInt(i int16) int64 {
	return int64(i)
}
func int32ToAuxInt(i int32) int64 {
	return int64(i)
}
func int64ToAuxInt(i int64) int64 {
	return int64(i)
}
func uint8ToAuxInt(i uint8) int64 {
	return int64(int8(i))
}
func float32ToAuxInt(f float32) int64 {
	return int64(math.Float64bits(float64(f)))
}
func float64ToAuxInt(f float64) int64 {
	return int64(math.Float64bits(f))
}
func valAndOffToAuxInt(v ValAndOff) int64 {
	return int64(v)
}
func arm64BitFieldToAuxInt(v arm64BitField) int64 {
	return int64(v)
}
func int128ToAuxInt(x int128) int64 {
	if x != 0 {
		panic("nonzero int128 not allowed")
	}
	return 0
}
func flagConstantToAuxInt(x flagConstant) int64 {
	return int64(x)
}

func opToAuxInt(o Op) int64 {
	return int64(o)
}

// Aux是以块和值形式保存杂项数据的接口。
type Aux interface {
	CanBeAnSSAAux()
}

// stringAux包装字符串值以在Aux中使用。
type stringAux string

func (stringAux) CanBeAnSSAAux() {}

func auxToString(i Aux) string {
	return string(i.(stringAux))
}
func auxToSym(i Aux) Sym {
	// TODO：一种黑客——允许nil接口通过
	s, _ := i.(Sym)
	return s
}
func auxToType(i Aux) *types.Type {
	return i.(*types.Type)
}
func auxToCall(i Aux) *AuxCall {
	return i.(*AuxCall)
}
func auxToS390xCCMask(i Aux) s390x.CCMask {
	return i.(s390x.CCMask)
}
func auxToS390xRotateParams(i Aux) s390x.RotateParams {
	return i.(s390x.RotateParams)
}

func StringToAux(s string) Aux {
	return stringAux(s)
}
func symToAux(s Sym) Aux {
	return s
}
func callToAux(s *AuxCall) Aux {
	return s
}
func typeToAux(t *types.Type) Aux {
	return t
}
func s390xCCMaskToAux(c s390x.CCMask) Aux {
	return c
}
func s390xRotateParamsToAux(r s390x.RotateParams) Aux {
	return r
}

// uaddOvf报告未签名的a+b是否会溢出。
func uaddOvf(a, b int64) bool {
	return uint64(a)+uint64(b) < uint64(a)
}

// 取消调用的虚拟化
// “sym”是itab的符号
func devirt(v *Value, aux Aux, sym Sym, offset int64) *AuxCall {
	f := v.Block.Func
	n, ok := sym.(*obj.LSym)
	if !ok {
		return nil
	}
	lsym := f.fe.DerefItab(n, offset)
	if f.pass.debug > 0 {
		if lsym != nil {
			f.Warnl(v.Pos, "de-virtualizing call")
		} else {
			f.Warnl(v.Pos, "couldn't de-virtualize call")
		}
	}
	if lsym == nil {
		return nil
	}
	va := aux.(*AuxCall)
	return StaticAuxCall(lsym, va.abiInfo)
}

// 取消中间调用的虚拟化
// “sym”是itab的符号
func devirtLESym(v *Value, aux Aux, sym Sym, offset int64) *obj.LSym {
	n, ok := sym.(*obj.LSym)
	if !ok {
		return nil
	}

	f := v.Block.Func
	lsym := f.fe.DerefItab(n, offset)
	if f.pass.debug > 0 {
		if lsym != nil {
			f.Warnl(v.Pos, "de-virtualizing call")
		} else {
			f.Warnl(v.Pos, "couldn't de-virtualize call")
		}
	}
	if lsym == nil {
		return nil
	}
	return lsym
}

func devirtLECall(v *Value, sym *obj.LSym) *Value {
	v.Op = OpStaticLECall
	auxcall := v.Aux.(*AuxCall)
	auxcall.Fn = sym
	v.RemoveArg(0)
	return v
}

// isSamePtr报告p1和p2是否指向同一地址。
func isSamePtr(p1, p2 *Value) bool {
	if p1 == p2 {
		return true
	}
	if p1.Op != p2.Op {
		return false
	}
	switch p1.Op {
	case OpOffPtr:
		return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
	case OpAddr, OpLocalAddr:
		// OpAddr的第0个参数是OpSP或OpSB，这意味着它由其Op唯一标识。
		// 只有在[z]cse运行后，才可以检查值是否相等。
		return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op
	case OpAddPtr:
		return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0])
	}
	return false
}

func isStackPtr(v *Value) bool {
	for v.Op == OpOffPtr || v.Op == OpAddPtr {
		v = v.Args[0]
	}
	return v.Op == OpSP || v.Op == OpLocalAddr
}

// disjoint报告由[p1:p1+n1]指定的内存区域
// 不与[p2:p2+n2]重叠。
// 返回值false并不意味着区域重叠。
func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool {
	if n1 == 0 || n2 == 0 {
		return true
	}
	if p1 == p2 {
		return false
	}
	baseAndOffset := func(ptr *Value) (base *Value, offset int64) {
		base, offset = ptr, 0
		for base.Op == OpOffPtr {
			offset += base.AuxInt
			base = base.Args[0]
		}
		return base, offset
	}
	p1, off1 := baseAndOffset(p1)
	p2, off2 := baseAndOffset(p2)
	if isSamePtr(p1, p2) {
		return !overlap(off1, n1, off2, n2)
	}
	// p1和p2不相同，因此如果它们都是opaddr，则
	// 它们指向不同的变量。
	// 如果一个指针在堆栈上，另一个是参数
	// 那么它们就不能重叠了。
	switch p1.Op {
	case OpAddr, OpLocalAddr:
		if p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpSP {
			return true
		}
		return (p2.Op == OpArg || p2.Op == OpArgIntReg) && p1.Args[0].Op == OpSP
	case OpArg, OpArgIntReg:
		if p2.Op == OpSP || p2.Op == OpLocalAddr {
			return true
		}
	case OpSP:
		return p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpArg || p2.Op == OpArgIntReg || p2.Op == OpSP
	}
	return false
}

// moveSize返回对齐MOV指令移动的字节数
func moveSize(align int64, c *Config) int64 {
	switch {
	case align%8 == 0 && c.PtrSize == 8:
		return 8
	case align%4 == 0:
		return 4
	case align%2 == 0:
		return 2
	}
	return 1
}

// mergePoint在a的块中找到一个块，该块控制b，并且是其自身
// 由a的所有区块控制。如果找不到，则返回nil。
// 即使存在，也可能返回nil。
func mergePoint(b *Block, a ...*Value) *Block {
	// 从b向后走，寻找a的一个街区。

	// 最大距离
	d := 100

	for d > 0 {
		for _, x := range a {
			if b == x.Block {
				goto found
			}
		}
		if len(b.Preds) > 1 {
			// 不知道该走哪条路回去。中止
			return nil
		}
		b = b.Preds[0].b
		d--
	}
	return nil // 太远
found:
	// 在这一点上，r是我们通过向后走找到的a中的第一个值。
	// 如果我们归还任何东西，r就是了。
	r := b

	// 继续，数一数我们找到的其他a。他们都必须控制r。
	na := 0
	for d > 0 {
		for _, x := range a {
			if b == x.Block {
				na++
			}
		}
		if na == len(a) {
			// 在向后走的过程中发现了所有的问题。我们可以返回r。
			return r
		}
		if len(b.Preds) > 1 {
			return nil
		}
		b = b.Preds[0].b
		d--

	}
	return nil // 太远
}

// clobber使值无效。返回true。
// 重写规则使用clobber来：
// A） 确保这些值真的死掉了，再也不用了。
// B） 递减使用值参数的计数。
func clobber(vv ...*Value) bool {
	for _, v := range vv {
		v.reset(OpInvalid)
		// 注意：保持v.块完好无损。块字段在clobber之后使用。
	}
	return true
}

// 当使用计数为1时，clobberIfDead重置v。返回true。
// 重写规则使用clobberIfDead递减
// 当v已死亡且从未使用时，使用v的参数计数。
func clobberIfDead(v *Value) bool {
	if v.Uses == 1 {
		v.reset(OpInvalid)
	}
	// 注意：保持v.块完好无损。块字段在ClobberRifDead之后使用。
	return true
}

// noteRule是一种在编写时跟踪规则是否匹配的简单方法
// 新的。使利益规则也以
// noteRule（“自我说明：利益匹配规则”）
// 当规则匹配时，将打印该消息。
func noteRule(s string) bool {
	fmt.Println(s)
	return true
}

// countRule递增函数规则匹配[key]。
// 如果Func.ruleMatches在结尾处为非nil
// 编译完成后，将打印到标准输出。
// 这是为了更容易找到哪些功能
// 在开发新规则时包含大量规则匹配。
func countRule(v *Value, key string) bool {
	f := v.Block.Func
	if f.ruleMatches == nil {
		f.ruleMatches = make(map[string]int)
	}
	f.ruleMatches[key]++
	return true
}

// warnRule在以下情况下使用字符串s生成编译器调试输出
// v不在自动生成的代码中，cond为true且已触发规则。
func warnRule(cond bool, v *Value, s string) bool {
	if pos := v.Pos; pos.Line() > 1 && cond {
		v.Block.Func.Warnl(pos, s)
	}
	return true
}

// 对于伪op-like（LessThan x），提取x
func flagArg(v *Value) *Value {
	if len(v.Args) != 1 || !v.Args[0].Type.IsFlags() {
		return nil
	}
	return v.Args[0]
}

// ARM64否定查找ARM64条件代码的补码，
// 例如相等->不相等或！小于->大于等于
// None
// 对于浮点，它更微妙，因为NaN是无序的。是的
// !LessThanF->NotLessThanF，后者负责南。
func arm64Negate(op Op) Op {
	switch op {
	case OpARM64LessThan:
		return OpARM64GreaterEqual
	case OpARM64LessThanU:
		return OpARM64GreaterEqualU
	case OpARM64GreaterThan:
		return OpARM64LessEqual
	case OpARM64GreaterThanU:
		return OpARM64LessEqualU
	case OpARM64LessEqual:
		return OpARM64GreaterThan
	case OpARM64LessEqualU:
		return OpARM64GreaterThanU
	case OpARM64GreaterEqual:
		return OpARM64LessThan
	case OpARM64GreaterEqualU:
		return OpARM64LessThanU
	case OpARM64Equal:
		return OpARM64NotEqual
	case OpARM64NotEqual:
		return OpARM64Equal
	case OpARM64LessThanF:
		return OpARM64NotLessThanF
	case OpARM64NotLessThanF:
		return OpARM64LessThanF
	case OpARM64LessEqualF:
		return OpARM64NotLessEqualF
	case OpARM64NotLessEqualF:
		return OpARM64LessEqualF
	case OpARM64GreaterThanF:
		return OpARM64NotGreaterThanF
	case OpARM64NotGreaterThanF:
		return OpARM64GreaterThanF
	case OpARM64GreaterEqualF:
		return OpARM64NotGreaterEqualF
	case OpARM64NotGreaterEqualF:
		return OpARM64GreaterEqualF
	default:
		panic("unreachable")
	}
}

// arm64Invert计算（InvertFlags op），其中
// 与更改条件代码相同，例如
// 如果参数
// 与标志生成指令相反，例如。
// （反转标志（CMP x y））->（CMP y x）
func arm64Invert(op Op) Op {
	switch op {
	case OpARM64LessThan:
		return OpARM64GreaterThan
	case OpARM64LessThanU:
		return OpARM64GreaterThanU
	case OpARM64GreaterThan:
		return OpARM64LessThan
	case OpARM64GreaterThanU:
		return OpARM64LessThanU
	case OpARM64LessEqual:
		return OpARM64GreaterEqual
	case OpARM64LessEqualU:
		return OpARM64GreaterEqualU
	case OpARM64GreaterEqual:
		return OpARM64LessEqual
	case OpARM64GreaterEqualU:
		return OpARM64LessEqualU
	case OpARM64Equal, OpARM64NotEqual:
		return op
	case OpARM64LessThanF:
		return OpARM64GreaterThanF
	case OpARM64GreaterThanF:
		return OpARM64LessThanF
	case OpARM64LessEqualF:
		return OpARM64GreaterEqualF
	case OpARM64GreaterEqualF:
		return OpARM64LessEqualF
	case OpARM64NotLessThanF:
		return OpARM64NotGreaterThanF
	case OpARM64NotGreaterThanF:
		return OpARM64NotLessThanF
	case OpARM64NotLessEqualF:
		return OpARM64NotGreaterEqualF
	case OpARM64NotGreaterEqualF:
		return OpARM64NotLessEqualF
	default:
		panic("unreachable")
	}
}

// 根据标志值计算ARM64 op
// 这可能是恒定的；返回1为真，
// -1表示假，0表示非常数。
func ccARM64Eval(op Op, flags *Value) int {
	fop := flags.Op
	if fop == OpARM64InvertFlags {
		return -ccARM64Eval(op, flags.Args[0])
	}
	if fop != OpARM64FlagConstant {
		return 0
	}
	fc := flagConstant(flags.AuxInt)
	b2i := func(b bool) int {
		if b {
			return 1
		}
		return -1
	}
	switch op {
	case OpARM64Equal:
		return b2i(fc.eq())
	case OpARM64NotEqual:
		return b2i(fc.ne())
	case OpARM64LessThan:
		return b2i(fc.lt())
	case OpARM64LessThanU:
		return b2i(fc.ult())
	case OpARM64GreaterThan:
		return b2i(fc.gt())
	case OpARM64GreaterThanU:
		return b2i(fc.ugt())
	case OpARM64LessEqual:
		return b2i(fc.le())
	case OpARM64LessEqualU:
		return b2i(fc.ule())
	case OpARM64GreaterEqual:
		return b2i(fc.ge())
	case OpARM64GreaterEqualU:
		return b2i(fc.uge())
	}
	return 0
}

// logRule记录规则s的使用情况。只有在以下情况下才会启用此功能：
// 重写规则是使用-log选项生成的，请参见gen/rulegen.go。
func logRule(s string) {
	if ruleFile == nil {
		// 打开要写入日志的日志文件。我们以追加方式打开
		// 模式，因为all.bash会多次运行编译器，
		// 我们需要所有这些日志的连接。
		// 当然，这意味着用户需要管理旧日志
		// 获取新数据。
		// TODO:all.bash并行运行编译器。需要以某种方式同步日志记录吗？
		w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
			os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			panic(err)
		}
		ruleFile = w
	}
	_, err := fmt.Fprintln(ruleFile, s)
	if err != nil {
		panic(err)
	}
}

var ruleFile io.Writer

func min(x, y int64) int64 {
	if x < y {
		return x
	}
	return y
}

func isConstZero(v *Value) bool {
	switch v.Op {
	case OpConstNil:
		return true
	case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConst32F, OpConst64F:
		return v.AuxInt == 0
	}
	return false
}

// reciprocalExact64报告1/c是否完全可表示。
func reciprocalExact64(c float64) bool {
	b := math.Float64bits(c)
	man := b & (1<<52 - 1)
	if man != 0 {
		return false // 不是2的幂、非正规或NaN
	}
	exp := b >> 52 & (1<<11 - 1)
	// 指数偏差为0x3ff。所以取一个数的倒数
	// 将指数更改为0x7fe-exp。
	switch exp {
	case 0:
		return false // ±0
	case 0x7ff:
		return false // ±inf
	case 0x7fe:
		return false // 指数是不可表示的
	default:
		return true
	}
}

// reciprocalExact32报告1/c是否完全可表示。
func reciprocalExact32(c float32) bool {
	b := math.Float32bits(c)
	man := b & (1<<23 - 1)
	if man != 0 {
		return false // 不是2的幂、非正规或NaN
	}
	exp := b >> 23 & (1<<8 - 1)
	// 指数偏差为0x7f。所以取一个数的倒数
	// 将指数更改为0xfe-exp。
	switch exp {
	case 0:
		return false // ±0
	case 0xff:
		return false // ±inf
	case 0xfe:
		return false // 指数是不可表示的
	default:
		return true
	}
}

// 检查立即数是否可以直接编码到ARM指令中
func isARMImmRot(v uint32) bool {
	for i := 0; i < 16; i++ {
		if v&^0xff == 0 {
			return true
		}
		v = v<<2 | v>>30
	}

	return false
}

// 重叠报告给定偏移量和
// 大小对重叠。
func overlap(offset1, size1, offset2, size2 int64) bool {
	if offset1 >= offset2 && offset2+size2 > offset1 {
		return true
	}
	if offset2 >= offset1 && offset1+size1 > offset2 {
		return true
	}
	return false
}

func areAdjacentOffsets(off1, off2, size int64) bool {
	return off1+size == off2 || off1 == off2+size
}

// 检查值是否将64位寄存器的上32位归零。
// 深度限制递归深度。在AMD64.3中，规则3用作限制，
// 因为它捕获的病例数量与4例相同。
func zeroUpper32Bits(x *Value, depth int) bool {
	switch x.Op {
	case OpAMD64MOVLconst, OpAMD64MOVLload, OpAMD64MOVLQZX, OpAMD64MOVLloadidx1,
		OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVBload, OpAMD64MOVBloadidx1,
		OpAMD64MOVLloadidx4, OpAMD64ADDLload, OpAMD64SUBLload, OpAMD64ANDLload,
		OpAMD64ORLload, OpAMD64XORLload, OpAMD64CVTTSD2SL,
		OpAMD64ADDL, OpAMD64ADDLconst, OpAMD64SUBL, OpAMD64SUBLconst,
		OpAMD64ANDL, OpAMD64ANDLconst, OpAMD64ORL, OpAMD64ORLconst,
		OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL,
		OpAMD64SHRL, OpAMD64SHRLconst, OpAMD64SARL, OpAMD64SARLconst,
		OpAMD64SHLL, OpAMD64SHLLconst:
		return true
	case OpArg:
		return x.Type.Width == 4
	case OpPhi, OpSelect0, OpSelect1:
		// PhI可以将彼此用作参数，而不是跟踪访问的值，
		// 只需限制递归深度。
		if depth <= 0 {
			return false
		}
		for i := range x.Args {
			if !zeroUpper32Bits(x.Args[i], depth-1) {
				return false
			}
		}
		return true

	}
	return false
}

// ZeroUpper48位与ZeroUpper32位类似，但适用于高48位
func zeroUpper48Bits(x *Value, depth int) bool {
	switch x.Op {
	case OpAMD64MOVWQZX, OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2:
		return true
	case OpArg:
		return x.Type.Width == 2
	case OpPhi, OpSelect0, OpSelect1:
		// PhI可以将彼此用作参数，而不是跟踪访问的值，
		// 只需限制递归深度。
		if depth <= 0 {
			return false
		}
		for i := range x.Args {
			if !zeroUpper48Bits(x.Args[i], depth-1) {
				return false
			}
		}
		return true

	}
	return false
}

// ZeroUpper56位类似于ZeroUpper32位，但适用于更高的56位
func zeroUpper56Bits(x *Value, depth int) bool {
	switch x.Op {
	case OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1:
		return true
	case OpArg:
		return x.Type.Width == 1
	case OpPhi, OpSelect0, OpSelect1:
		// PhI可以将彼此用作参数，而不是跟踪访问的值，
		// 只需限制递归深度。
		if depth <= 0 {
			return false
		}
		for i := range x.Args {
			if !zeroUpper56Bits(x.Args[i], depth-1) {
				return false
			}
		}
		return true

	}
	return false
}

// IsInLinableMove报告给定拱门是否执行给定大小的移动
// 比移动速度快。仅当需要将memmove替换为Move时，才会返回true
// 安全，要么因为移动很小，要么因为参数不相交。
// 这用于检查是否将memmove替换为Move ops。
func isInlinableMemmove(dst, src *Value, sz int64, c *Config) bool {
	// 当memmove的参数不相交时，将其转换为Move总是安全的。
	// 对于大尺寸，移动操作可能更快，也可能更快，这取决于平台的工作方式
	// 降低了它们，所以我们只在已知的平台上执行此优化
	// 快速行动。
	switch c.arch {
	case "amd64":
		return sz <= 16 || (sz < 1024 && disjoint(dst, sz, src, sz))
	case "386", "arm64":
		return sz <= 8
	case "s390x", "ppc64", "ppc64le":
		return sz <= 8 || disjoint(dst, sz, src, sz)
	case "arm", "mips", "mips64", "mipsle", "mips64le":
		return sz <= 4
	}
	return false
}

// logLargeCopy记录大副本的发生。
// 最好的方法是在重写规则中找到移动的大小。
// “大”任意选择为128字节；这可能会改变。
func logLargeCopy(v *Value, s int64) bool {
	if s < 128 {
		return true
	}
	if logopt.Enabled() {
		logopt.LogOpt(v.Pos, "copy", "lower", v.Block.Func.Name, fmt.Sprintf("%d bytes", s))
	}
	return true
}

// hasSmallRotate报告体系结构是否具有旋转指令
// 对于小于32位的大小。这用于决定是否促进某些旋转。
func hasSmallRotate(c *Config) bool {
	switch c.arch {
	case "amd64", "386":
		return true
	default:
		return false
	}
}

func newPPC64ShiftAuxInt(sh, mb, me, sz int64) int32 {
	if sh < 0 || sh >= sz {
		panic("PPC64 shift arg sh out of range")
	}
	if mb < 0 || mb >= sz {
		panic("PPC64 shift arg mb out of range")
	}
	if me < 0 || me >= sz {
		panic("PPC64 shift arg me out of range")
	}
	return int32(sh<<16 | mb<<8 | me)
}

func GetPPC64Shiftsh(auxint int64) int64 {
	return int64(int8(auxint >> 16))
}

func GetPPC64Shiftmb(auxint int64) int64 {
	return int64(int8(auxint >> 8))
}

func GetPPC64Shiftme(auxint int64) int64 {
	return int64(int8(auxint))
}

// 测试此值是否可以编码为类似rlwinm的掩码
// 活动遮罩也可以从msb延伸并包裹到
// lsb也是。也就是说，有效掩码是32位字符串
// 形式：0..01..10..0或1..10..01..1或1..1
func isPPC64WordRotateMask(v64 int64) bool {
	// 隔离最右边的1（如果没有0）并添加。
	v := uint32(v64)
	vp := (v & -v) + v
	// 同样，对于包装箱。
	vn := ^v
	vpn := (vn & -vn) + vn
	return (v&vp == 0 || vn&vpn == 0) && v != 0
}

// 压缩掩码并将其转换为表单的单个值
// me | mb<<8 |旋转<<16 | nbits<<24，在me和mb可以旋转的地方
// 用于重新生成输入掩码。
func encodePPC64RotateMask(rotate, mask, nbits int64) int64 {
	var mb, me, mbn, men int

	// 确定边界，然后解码它们
	if mask == 0 || ^mask == 0 || rotate >= nbits {
		panic("Invalid PPC64 rotate mask")
	} else if nbits == 32 {
		mb = bits.LeadingZeros32(uint32(mask))
		me = 32 - bits.TrailingZeros32(uint32(mask))
		mbn = bits.LeadingZeros32(^uint32(mask))
		men = 32 - bits.TrailingZeros32(^uint32(mask))
	} else {
		mb = bits.LeadingZeros64(uint64(mask))
		me = 64 - bits.TrailingZeros64(uint64(mask))
		mbn = bits.LeadingZeros64(^uint64(mask))
		men = 64 - bits.TrailingZeros64(^uint64(mask))
	}
	// 检查包装掩码（例如0和63处的位）
	if mb == 0 && me == int(nbits) {
		// 交换反转的值
		mb, me = men, mbn
	}

	return int64(me) | int64(mb<<8) | int64(rotate<<16) | int64(nbits<<24)
}

// encodePPC64RotateMask的逆运算。返回的值为
// mb和me满足掩码（x，y）的幂ISA定义，其中掩码（mb，me）=掩码。
func DecodePPC64RotateMask(sauxint int64) (rotate, mb, me int64, mask uint64) {
	auxint := uint64(sauxint)
	rotate = int64((auxint >> 16) & 0xFF)
	mb = int64((auxint >> 8) & 0xFF)
	me = int64((auxint >> 0) & 0xFF)
	nbits := int64((auxint >> 24) & 0xFF)
	mask = ((1 << uint(nbits-mb)) - 1) ^ ((1 << uint(nbits-me)) - 1)
	if mb > me {
		mask = ^mask
	}
	if nbits == 32 {
		mask = uint64(uint32(mask))
	}

	// 让我符合ISA的定义。掩盖的第二个参数（..，我）
	// 是包容性的。
	me = (me - 1) & (nbits - 1)
	return
}

// 这将验证掩码是否是一组
// 包括最小值的连续位
// 有效位。
func isPPC64ValidShiftMask(v int64) bool {
	if (v != 0) && ((v+1)&v) == 0 {
		return true
	}
	return false
}

func getPPC64ShiftMaskLength(v int64) int64 {
	return int64(bits.Len64(uint64(v)))
}

// 将右移分解为等效的旋转/遮罩，
// 和返回掩码&m。
func mergePPC64RShiftMask(m, s, nbits int64) int64 {
	smask := uint64((1<<uint(nbits))-1) >> uint(s)
	return m & int64(smask)
}

// 将（ANDconst[m]（SRWconst[s]）合并到（RLWINM[y]）中或返回0
func mergePPC64AndSrwi(m, s int64) int64 {
	mask := mergePPC64RShiftMask(m, s, 32)
	if !isPPC64WordRotateMask(mask) {
		return 0
	}
	return encodePPC64RotateMask((32-s)&31, mask, 32)
}

// 测试输入CLRLLDI的右移是否可以合并到RLWINM中。
// 返回编码的RLWINM常量，如果无法合并，则返回0。
func mergePPC64ClrlsldiSrw(sld, srw int64) int64 {
	mask_1 := uint64(0xFFFFFFFF >> uint(srw))
	// 对于CLRLDI，更方便的做法是将其视为左位掩码，然后向左旋转。
	mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))

	// 重写掩码以在最后一次左移后应用。
	mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(sld))

	r_1 := 32 - srw
	r_2 := GetPPC64Shiftsh(sld)
	r_3 := (r_1 + r_2) & 31 // 这个可以包起来。

	if uint64(uint32(mask_3)) != mask_3 || mask_3 == 0 {
		return 0
	}
	return encodePPC64RotateMask(int64(r_3), int64(mask_3), 32)
}

// 测试传入CLRLLDI的RLWINM是否可以合并到RLWINM中。回来
// 编码的RLWINM常量，如果无法合并，则为0。
func mergePPC64ClrlsldiRlwinm(sld int32, rlw int64) int64 {
	r_1, _, _, mask_1 := DecodePPC64RotateMask(rlw)
	// 对于CLRLDI，更方便的做法是将其视为左位掩码，然后向左旋转。
	mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))

	// 组合遮罩，并调整到最后的左移。
	mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(int64(sld)))
	r_2 := GetPPC64Shiftsh(int64(sld))
	r_3 := (r_1 + r_2) & 31 // 这个可以包起来。

	// 验证结果是否仍然是小于等于32位的有效位掩码。
	if !isPPC64WordRotateMask(int64(mask_3)) || uint64(uint32(mask_3)) != mask_3 {
		return 0
	}
	return encodePPC64RotateMask(r_3, int64(mask_3), 32)
}

// 通过组合（SLDconst[sld]（SRWconst[srw]x））计算编码的RLWINM常量，
// 如果不能组合，则返回0。
func mergePPC64SldiSrw(sld, srw int64) int64 {
	if sld > srw || srw >= 32 {
		return 0
	}
	mask_r := uint32(0xFFFFFFFF) >> uint(srw)
	mask_l := uint32(0xFFFFFFFF) >> uint(sld)
	mask := (mask_r & mask_l) << uint(sld)
	return encodePPC64RotateMask((32-srw+sld)&31, int64(mask), 32)
}

// 将32位常量值旋转另一个常量的便利函数。
func rotateLeft32(v, rotate int64) int64 {
	return int64(bits.RotateLeft32(uint32(v), int(rotate)))
}

// 将arm（64）位字段操作的lsb和宽度编码为预期的auxInt格式。
func armBFAuxInt(lsb, width int64) arm64BitField {
	if lsb < 0 || lsb > 63 {
		panic("ARM(64) bit field lsb constant out of range")
	}
	if width < 1 || width > 64 {
		panic("ARM(64) bit field width constant out of range")
	}
	return arm64BitField(width | lsb<<8)
}

// 返回arm64位字段ops的生长素字段的lsb部分。
func (bfc arm64BitField) getARM64BFlsb() int64 {
	return int64(uint64(bfc) >> 8)
}

// 返回arm64位字段ops的生长素字段的宽度部分。
func (bfc arm64BitField) getARM64BFwidth() int64 {
	return int64(bfc) & 0xff
}

// 检查lsb上应用的掩码>>rshift是否为有效的arm64位字段操作掩码。
func isARM64BFMask(lsb, mask, rshift int64) bool {
	shiftedMask := int64(uint64(mask) >> uint64(rshift))
	return shiftedMask != 0 && isPowerOfTwo64(shiftedMask+1) && nto(shiftedMask)+lsb < 64
}

// 返回arm64位字段操作的掩码>>rshift的位字段宽度
func arm64BFWidth(mask, rshift int64) int64 {
	shiftedMask := int64(uint64(mask) >> uint64(rshift))
	if shiftedMask == 0 {
		panic("ARM64 BF mask is zero")
	}
	return nto(shiftedMask)
}

// sizeof返回t的大小（以字节为单位）。
// 如果t不是*types.Type，它将死机。
func sizeof(t interface{}) int64 {
	return t.(*types.Type).Size()
}

// registerizable报告t是否是适合的基元类型
// 登记册。它假定float64值始终适合于寄存器
// 即使严格来说这不是真的。
func registerizable(b *Block, typ *types.Type) bool {
	if typ.IsPtrShaped() || typ.IsFloat() {
		return true
	}
	if typ.IsInteger() {
		return typ.Size() <= b.Func.Config.RegSize
	}
	return false
}

// needRaceCleanup报告是否不需要调用racefuncenter/exit。
func needRaceCleanup(sym *AuxCall, v *Value) bool {
	f := v.Block.Func
	if !f.Config.Race {
		return false
	}
	if !isSameCall(sym, "runtime.racefuncenter") && !isSameCall(sym, "runtime.racefuncexit") {
		return false
	}
	for _, b := range f.Blocks {
		for _, v := range b.Values {
			switch v.Op {
			case OpStaticCall, OpStaticLECall:
				// 检查racefuncenter将遇到racefuncexit，反之亦然。
				// 允许呼叫暂停*
				s := v.Aux.(*AuxCall).Fn.String()
				switch s {
				case "runtime.racefuncenter", "runtime.racefuncexit",
					"runtime.panicdivide", "runtime.panicwrap",
					"runtime.panicshift":
					continue
				}
				// 如果遇到任何呼叫，我们需要保留racefunc*，
				// 用于精确的堆栈跟踪。
				return false
			case OpPanicBounds, OpPanicExtend:
				// 注意：这些是正常的紧急生成器（如上面的静态调用）。
			case OpClosureCall, OpInterCall, OpClosureLECall, OpInterLECall:
				// 如果有其他调用类型，我们必须保留race函数。
				return false
			}
		}
	}
	if isSameCall(sym, "runtime.racefuncenter") {
		// TODO注册ABI这需要清理。
		// 如果要删除racefuncenter，请同时删除其参数。
		if v.Args[0].Op != OpStore {
			if v.Op == OpStaticLECall {
				// 现在还没有商店。
				return true
			}
			return false
		}
		mem := v.Args[0].Args[2]
		v.Args[0].reset(OpCopy)
		v.Args[0].AddArg(mem)
	}
	return true
}

// symIsRO报告sym是否为只读全局。
func symIsRO(sym interface{}) bool {
	lsym := sym.(*obj.LSym)
	return lsym.Type == objabi.SRODATA && len(lsym.R) == 0
}

// symIsROZero报告sym是否为只读全局，其数据包含全零。
func symIsROZero(sym Sym) bool {
	lsym := sym.(*obj.LSym)
	if lsym.Type != objabi.SRODATA || len(lsym.R) != 0 {
		return false
	}
	for _, b := range lsym.P {
		if b != 0 {
			return false
		}
	}
	return true
}

// read8在偏移量off时从只读全局sym读取一个字节。
func read8(sym interface{}, off int64) uint8 {
	lsym := sym.(*obj.LSym)
	if off >= int64(len(lsym.P)) || off < 0 {
		// 全局符号的索引无效。
		// 这可能发生在死代码中，所以我们不想惊慌失措。
		// 只要返回任何值，它最终将被忽略。
		// 见第29215期。
		return 0
	}
	return lsym.P[off]
}

// read16在offset off处从只读全局sym读取两个字节。
func read16(sym interface{}, off int64, byteorder binary.ByteOrder) uint16 {
	lsym := sym.(*obj.LSym)
	// lsym.P是惰性编写的。
	// lsym.P结束后请求的字节数为0。
	var src []byte
	if 0 <= off && off < int64(len(lsym.P)) {
		src = lsym.P[off:]
	}
	buf := make([]byte, 2)
	copy(buf, src)
	return byteorder.Uint16(buf)
}

// read32在offset off处从只读全局sym读取四个字节。
func read32(sym interface{}, off int64, byteorder binary.ByteOrder) uint32 {
	lsym := sym.(*obj.LSym)
	var src []byte
	if 0 <= off && off < int64(len(lsym.P)) {
		src = lsym.P[off:]
	}
	buf := make([]byte, 4)
	copy(buf, src)
	return byteorder.Uint32(buf)
}

// read64在offset off处从只读全局sym读取八个字节。
func read64(sym interface{}, off int64, byteorder binary.ByteOrder) uint64 {
	lsym := sym.(*obj.LSym)
	var src []byte
	if 0 <= off && off < int64(len(lsym.P)) {
		src = lsym.P[off:]
	}
	buf := make([]byte, 8)
	copy(buf, src)
	return byteorder.Uint64(buf)
}

// 如果可以证明x+n==y，则sequentialAddresses报告true
func sequentialAddresses(x, y *Value, n int64) bool {
	if x.Op == Op386ADDL && y.Op == Op386LEAL1 && y.AuxInt == n && y.Aux == nil &&
		(x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
			x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
		return true
	}
	if x.Op == Op386LEAL1 && y.Op == Op386LEAL1 && y.AuxInt == x.AuxInt+n && x.Aux == y.Aux &&
		(x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
			x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
		return true
	}
	if x.Op == OpAMD64ADDQ && y.Op == OpAMD64LEAQ1 && y.AuxInt == n && y.Aux == nil &&
		(x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
			x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
		return true
	}
	if x.Op == OpAMD64LEAQ1 && y.Op == OpAMD64LEAQ1 && y.AuxInt == x.AuxInt+n && x.Aux == y.Aux &&
		(x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
			x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
		return true
	}
	return false
}

// flagConstant表示编译时比较的结果。
// 这些标志的意义并不一定代表硬件的概念
// 这些只是编译时构造。
// 我们碰巧将语义与arm/arm64的语义相匹配。
// 请注意，这些语义不同于x86：进位标志具有相反的含义
// 减法的意义！
// 在amd64上，C=1表示借用，例如，amd64上的SBB执行x-y-C。
// 在arm64上，C=0表示借用，例如，arm64上的SBC执行x-y-^C。
// （因为它有x+^y+C）。
// 请参阅https:
type flagConstant uint8

// N报告操作结果是否为负（高位设置）。
func (fc flagConstant) N() bool {
	return fc&1 != 0
}

// Z报告操作的结果是否为0。
func (fc flagConstant) Z() bool {
	return fc&2 != 0
}

// C报告未签名的加法是否溢出（进位），或
// 无符号减法未下溢（借用）。
func (fc flagConstant) C() bool {
	return fc&4 != 0
}

// V报告已签名的操作是溢出还是下溢。
func (fc flagConstant) V() bool {
	return fc&8 != 0
}

func (fc flagConstant) eq() bool {
	return fc.Z()
}
func (fc flagConstant) ne() bool {
	return !fc.Z()
}
func (fc flagConstant) lt() bool {
	return fc.N() != fc.V()
}
func (fc flagConstant) le() bool {
	return fc.Z() || fc.lt()
}
func (fc flagConstant) gt() bool {
	return !fc.Z() && fc.ge()
}
func (fc flagConstant) ge() bool {
	return fc.N() == fc.V()
}
func (fc flagConstant) ult() bool {
	return !fc.C()
}
func (fc flagConstant) ule() bool {
	return fc.Z() || fc.ult()
}
func (fc flagConstant) ugt() bool {
	return !fc.Z() && fc.uge()
}
func (fc flagConstant) uge() bool {
	return fc.C()
}

func (fc flagConstant) ltNoov() bool {
	return fc.lt() && !fc.V()
}
func (fc flagConstant) leNoov() bool {
	return fc.le() && !fc.V()
}
func (fc flagConstant) gtNoov() bool {
	return fc.gt() && !fc.V()
}
func (fc flagConstant) geNoov() bool {
	return fc.ge() && !fc.V()
}

func (fc flagConstant) String() string {
	return fmt.Sprintf("N=%v,Z=%v,C=%v,V=%v", fc.N(), fc.Z(), fc.C(), fc.V())
}

type flagConstantBuilder struct {
	N bool
	Z bool
	C bool
	V bool
}

func (fcs flagConstantBuilder) encode() flagConstant {
	var fc flagConstant
	if fcs.N {
		fc |= 1
	}
	if fcs.Z {
		fc |= 2
	}
	if fcs.C {
		fc |= 4
	}
	if fcs.V {
		fc |= 8
	}
	return fc
}

// 注意：添加标志（x，y）！=在某些情况下，子标签（x，-y）：
// -C标志的结果是不同的
// -当y==minint时，V标志的结果不同

// addFlags64返回将通过计算x+y设置的标志。
func addFlags64(x, y int64) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x+y == 0
	fcb.N = x+y < 0
	fcb.C = uint64(x+y) < uint64(x)
	fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
	return fcb.encode()
}

// subFlags64返回将通过计算x-y设置的标志。
func subFlags64(x, y int64) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x-y == 0
	fcb.N = x-y < 0
	fcb.C = uint64(y) <= uint64(x) // 此代码遵循手臂携带标志模型。
	fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
	return fcb.encode()
}

// addFlags32返回将通过计算x+y设置的标志。
func addFlags32(x, y int32) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x+y == 0
	fcb.N = x+y < 0
	fcb.C = uint32(x+y) < uint32(x)
	fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
	return fcb.encode()
}

// subFlags32返回将通过计算x-y设置的标志。
func subFlags32(x, y int32) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x-y == 0
	fcb.N = x-y < 0
	fcb.C = uint32(y) <= uint32(x) // 此代码遵循手臂携带标志模型。
	fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
	return fcb.encode()
}

// logicFlags64返回设置为x的符号/零的标志。
// C和V设置为false。
func logicFlags64(x int64) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x == 0
	fcb.N = x < 0
	return fcb.encode()
}

// logicFlags32返回设置为x的符号/零的标志。
// C和V设置为false。
func logicFlags32(x int32) flagConstant {
	var fcb flagConstantBuilder
	fcb.Z = x == 0
	fcb.N = x < 0
	return fcb.encode()
}
